import Map from 'ol/Map';
import {getArea, getDistance, getLength} from "ol/sphere";
import Overlay from "ol/Overlay";
import {toLonLat} from "ol/proj";
import {Draw, Modify, Snap} from "ol/interaction";
import SourceVector from "ol/source/Vector";
import LayerVector from "ol/layer/Vector";

import MapStyle from "@/view/gis/map-style";
import Text from "@/lang/layers/text";

/**
 * 地图计算距离的工具
 *
 * 在地图上，拉一条线，计算这条线的实际距离
 */
export class Distance {

    map: Map;

    constructor(map: Map) {
        let sourceVector = new SourceVector();

        // 一个空白图层，可以理解成画布，我们要在上面绘制各种图形
        let layerVector = new LayerVector({
            source: sourceVector,
            style: MapStyle.defaultStyle
        });

        // 是否正在绘制
        let drawing = false;
        // 第一个点
        let first;

        // 地图绘制
        const draw = new Draw({
            maxPoints: 2,
            type: 'LineString',
            source: sourceVector
        });

        // 优化操作，自动吸附鼠标附近的元素
        const snap = new Snap({source: sourceVector});

        // 数据格式化输出
        const format = (distance: number) => {
            if (distance > 1000) {
                return "两点之间的距离为：" + Text.round2(distance / 1000) + " 公里"
            } else {
                return "两点之间的距离为：" + Text.round2(distance) + " 米"
            }
        }

        // 绘制开始事件
        draw.on('drawstart', function (evt) {
            drawing = true;
            first = evt.feature.getGeometry().getCoordinates()[0];

            // 清除历史绘制
            sourceVector.clear();

            htmlOverlay.setPosition(first);
            span.textContent = format(0);
            element.style.display = '';
        });

        // 绘制结束事件
        draw.on('drawend', function (evt) {
            drawing = false;
            const line = evt.feature.getGeometry();
            const distance = getLength(line);
            span.textContent = format(distance);
        });

        // 通过 innerHTML 添加 HTML 内容作为 Overlay
        const element: HTMLElement = document.createElement('div');
        element.classList.add('sea-float-box');
        element.innerHTML = `
            <div class="float-top arrow-after-bottom" style="left: -19px;bottom: 16px;width: 110px;">
              <span>popover</span>
            </div>
        `;
        element.style.display = 'none';

        const htmlOverlay = new Overlay({
            position: map.getView().getCenter(),
            element: element,
            positioning: 'top-center'
        });

        const span = element.querySelector('span:first-child');

        const pointermove = (evt) => {
            if (drawing) {
                let coordinate = evt.coordinate;

                htmlOverlay.setPosition(coordinate);

                const distance = getDistance(toLonLat(first), toLonLat(coordinate));
                span.innerHTML = format(distance);
            }
        }


        // layer
        this.layer = layerVector;
        this.overlay = htmlOverlay;

        // interaction
        this.draw = draw;
        this.snap = snap;

        // event
        this.pointermove = pointermove;

        // map
        this.map = map;

        map.on('pointermove', pointermove);

        map.addLayer(this.layer)
        map.addOverlay(this.overlay);
        map.addInteraction(this.draw);
        map.addInteraction(this.snap);
    }

    /**
     * 销毁相关组件
     */
    destroy() {
        this.map.un('pointermove', pointermove);

        this.map.removeLayer(this.layer);
        this.map.removeOverlay(this.overlay);
        this.map.removeInteraction(this.draw);
        this.map.removeInteraction(this.snap);
    }
}

/**
 * 计算面积
 *
 * 在地图上画一个几何图形，画完之后计算图形的面积，
 * 当前功能通过 open-layer 内置函数实现。
 *
 * other plans：通过点击事件实现，自动连接首尾端点，实时计算区域面积。
 * tips：因为只是玩具，没啥优化的必要。
 */
export class Area {

    map: Map;

    constructor(map: Map) {
        let sourceVector = new SourceVector();

        // 一个空白图层，可以理解成画布，我们要在上面绘制各种图形
        let layerVector = new LayerVector({
            source: sourceVector,
            style: MapStyle.defaultStyle
        });

        // 是否正在绘制
        let drawing = false;
        // 第一个点
        let first;

        // 地图绘制
        const draw = new Draw({
            type: 'Polygon',
            source: sourceVector
        });

        // 优化操作，自动吸附鼠标附近的元素
        const snap = new Snap({source: sourceVector});
        const modify = new Modify({source: sourceVector});

        // 数据格式化输出
        const format = (distance: number) => {
            if (distance > 1000_000) {
                return "圈画的面积为：" + Text.round2(distance / 1000_000) + " 平方公里"
            } else {
                return "圈画的面积为：" + Text.round2(distance) + " 平方米"
            }
        }

        // 绘制开始事件
        draw.on('drawstart', function (evt) {
            drawing = true;
            first = evt.feature.getGeometry().getCoordinates()[0];

            // 清除历史绘制
            sourceVector.clear();

            // 悬浮气泡窗口
            element.style.display = 'none';
        });

        // 绘制结束事件
        draw.on('drawend', function (evt) {
            drawing = false;
            const line = evt.feature.getGeometry();

            const first = line.getCoordinates()[0][0];
            htmlOverlay.setPosition(first);

            const spherical = getArea(line);
            span.textContent = format(spherical);
            element.style.display = '';

            line.on('change', () => {
                const first = line.getCoordinates()[0][0];
                htmlOverlay.setPosition(first);

                const spherical = getArea(line);
                span.textContent = format(spherical);
            });
        });

        // 绘制结束事件
        draw.on('change', function (evt) {
            const line = evt.feature.getGeometry();
            const spherical = getArea(line);
            span.textContent = format(spherical);
        });

        // 通过 innerHTML 添加 HTML 内容作为 Overlay
        const element: HTMLElement = document.createElement('div');
        element.classList.add('sea-float-box');
        element.innerHTML = `
            <div class="float-top arrow-after-bottom" style="left: -19px;bottom: 16px;width: 110px;">
              <span>popover</span>
            </div>
        `;
        element.style.display = 'none';

        const htmlOverlay = new Overlay({
            position: map.getView().getCenter(),
            element: element,
            positioning: 'top-center'
        });

        const span = element.querySelector('span:first-child');

        // layer
        this.layer = layerVector;
        this.overlay = htmlOverlay;

        // interaction
        this.draw = draw;
        this.snap = snap;
        this.modify = modify;


        // map
        this.map = map;

        map.addLayer(this.layer)
        map.addOverlay(this.overlay);
        map.addInteraction(this.draw);
        map.addInteraction(this.snap);
        map.addInteraction(this.modify);
    }

    /**
     * 销毁相关组件
     */
    destroy() {
        this.map.removeLayer(this.layer);
        this.map.removeOverlay(this.overlay);
        this.map.removeInteraction(this.draw);
        this.map.removeInteraction(this.snap);
        this.map.removeInteraction(this.modify);
    }
}


/**
 * 获取当前比例尺
 *
 * 因为屏幕 dpi 不固定，因此存在严重误差；
 *
 * 浏览器的所有内容，本身就会受到分辨率的影响，算比例尺意义不大。
 *
 * @param map -
 */
function getScale(map) {
    const view = map.getView();
    const resolution = view.getResolution(); // 分辨率（米/像素）
    const dpi = 96; // 假设屏幕为 96 DPI
    const inchesPerMeter = 39.37; // 1 米 = 39.37 英寸
    return resolution * dpi * inchesPerMeter;
}
